import inspect
from typing import Union
from abc import ABCMeta, abstractmethod
from functools import wraps
from Common import *


class BaseDriver(object):
    __metaclass__ = ABCMeta

    @classmethod
    def get_method_names(cls, method_prefix=None):
        if method_prefix is None:
            return (list(filter(
                lambda m: not m.startswith("_") and not m.endswith("__") and inspect.isfunction(getattr(cls, m)),
                dir(cls))))
        else:
            return (list(
                filter(lambda m: m.startswith(method_prefix) and not m.endswith("__") and inspect.isfunction(getattr(cls, m)),
                       dir(cls))))

    @classmethod
    def get_method_args(cls, method_name):
        try:
            m = getattr(cls, method_name)
            return [s for s in inspect.signature(m).parameters.keys() if s != 'self']
        except:
            return []

    @abstractmethod
    def device_connect(self):
        """
        连接设备
        :return:
        """

    @abstractmethod
    def device_disconnect(self):
        """
        断开连接
        :return:
        """

    ###########################################################################
    # driver方法
    ###########################################################################
    @abstractmethod
    def session_click(self, x: float, y: float):
        """
        点击事件
        :param x: x坐标
        :param y: y坐标
        :return:
        """

    @abstractmethod
    def session_swipe(self, fx: int, fy: int, tx: int, ty: int):
        """
        滑动事件
        :param fx: 起点x坐标
        :param fy: 起点y坐标
        :param tx: 终点x坐标
        :param ty: 终点y坐标
        :return:
        """

    @abstractmethod
    def session_system(self, key: Union[int, str]):
        """
        系统按键事件
        :param key: 按键名
        :return:
        """

    @abstractmethod
    def session_info(self):
        """
        系统信息
        :return:
        """

    @abstractmethod
    def session_screenshot(self):
        """
        截图
        :return:
        """

    @abstractmethod
    def session_dump(self):
        """
        获取xml控件树
        :return:
        """

    @abstractmethod
    def session_windows(self):
        """
        获取设备显示大小
        :return:
        """

    @abstractmethod
    def _android_hierarchy_to_json(self, d):
        """
        获取控件树
        :param d: client
        :return:
        """

    ###########################################################################
    # driver方法
    ###########################################################################
    @abstractmethod
    def app_start(self, app: str):
        """
        启动app
        :param app: app包名
        :return:
        """

    @abstractmethod
    def app_stop(self, app: str):
        """
        停止app
        :param app: app包名
        :return:
        """

    @abstractmethod
    def app_restart(self, app: str):
        """
        重启app
        :param app: app包名
        :return:
        """

    @abstractmethod
    def app_reset(self, app: str):
        """
        重置app
        :param app: app包名
        :return:
        """

    ###########################################################################
    # element方法
    ###########################################################################
    @abstractmethod
    def element_click(self, locator):
        """
        点击控件
        :param locator: 控件定位器
        :return:
        """

    @abstractmethod
    def element_send(self, locator, text: str):
        """
        向控件发送文字
        :param locator: 控件定位器
        :param text: 文本
        :return:
        """

    @abstractmethod
    def element_clear(self, locator):
        """
        清空控件文本
        :param locator: 控件定位器
        :return:
        """

    @abstractmethod
    def element_exists(self, locator):
        """
        判断控件是否存在
        :param locator: 控件定位器
        :return:
        """

    @abstractmethod
    def element_info(self, locator):
        """
        获取控件信息
        :param locator: 控件定位器
        :return:
        """

    ###########################################################################
    # find方法
    ###########################################################################
    @abstractmethod
    def find_element(self, locator):
        """
        查找控件
        :param locator: 控件定位器
        :return:
        """

    @abstractmethod
    def find_elements(self, locator):
        """
        查找控件（多个）
        :param locator: 控件定位器
        :return:
        """

    @abstractmethod
    def find_allinfo(self, locator):
        pass


def check_status(func):
    @wraps(func)
    def check(self, *args, **kwargs):
        if self.status == 'connect':
            res = func(self, *args, **kwargs)
            return res if res is not None else ""
        else:
            raise ClientRunError('driver status is not connect')
    return check
